#include <pfring.h>
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>

#include <sys/prctl.h>
#include <signal.h>

#include "common.h"
#include "change.h"

#define MAX_PACKET_SIZE 1500
int recv_num_i = 0;

void print_packet(const struct pfring_pkthdr *h, const u_char *p, u_int8_t dump_match)
{
    u_char *p_tmp = p;
    if (*(p_tmp + 34) != 0)
        return;
    if (*(p_tmp + 35) != 0)
        return;

    // printf("%x\n", *(p_tmp + 34));
    struct PING_PACKET ping_packet;

    memcpy(&(ping_packet.frame_header), p, 14);
    memcpy(&(ping_packet.ip_header), p + 14, 20);
    memcpy(&(ping_packet.icmp_echo), p + 34, 24);

    recv_num_i++;
    // printf("recieved:%d--%d\n", ntohs(ping_packet.icmp_echo.seq), recv_num_i);

    struct FRAME_HEADER *frame_header = &(ping_packet.frame_header);
    struct IP_HEADER *ip_header = &(ping_packet.ip_header);
    struct ICMP_ECHO *icmp_echo = &(ping_packet.icmp_echo);

    struct timeval tv_now; // 发送时间戳
    gettimeofday(&tv_now, NULL);
    float time_interval = calculate_time_interval(&(icmp_echo->tv), &tv_now);
    for (int i = 0; i < 40; i++)
    {
        printf("%x ", *(p_tmp + i));

        if (i == 13)
            printf("\n");
        if (i > 14 && (i - 14) % 4 == 3)
            printf("\n");
    }

    printf("%d bytes from %s:icmp_seq=%d time=%.3f ms\n", sizeof(ping_packet), inet_ntoa(ip_header->sour_ip), htons(icmp_echo->seq), time_interval);
}

int main(int argc, char *argv[])
{
    char *device_name = "ens33";
    u_int32_t flags = 265;

    // u_int32_t flags = 0;
    pfring *ring = pfring_open(device_name, DEFAULT_SNAPLEN, flags);

    if (ring == NULL)
        return -1;

    pid_t fpid = fork();
    if (fpid == 0)
    {
        prctl(PR_SET_PDEATHSIG, SIGKILL);

        struct pfring_pkthdr hdr;
        u_char *buffer = NULL;
        int rc = 0;

        memset(&hdr, 0, sizeof(hdr));
        ring->break_recv_loop = ring->break_recv_loop_ext = 0;

        if ((!ring) || ring->is_shutting_down || (!ring->recv) || ring->mode == send_only_mode)
            return -1;

        while (!ring->break_recv_loop_ext)
        {
            rc = ring->recv(ring, &buffer, 0, &hdr, 1);
            // pfring_recv(ring, &buffer, 0, &hdr, 1);
            print_packet(&hdr, buffer, NULL);
        }
    }
    else
    {
        printf("created\n");

        // 构造帧头部
        struct PING_PACKET ping_packet;

        struct FRAME_HEADER *frame_header = &(ping_packet.frame_header);
        struct IP_HEADER *ip_header = &(ping_packet.ip_header);
        struct ICMP_ECHO *icmp_echo = &(ping_packet.icmp_echo);

        int len_frame_header = 0, len_ip_header = 0, len_icmp_echo = 0;

        len_frame_header = sizeof(*frame_header);
        len_ip_header = sizeof(*ip_header);
        len_icmp_echo = sizeof(*icmp_echo);

        // char smac_char[18] = "00:0c:29:f8:81:8d";
        // mac_char_to_u_char(smac_char, &(frame_header->smac));

        pfring_get_bound_device_address(ring, frame_header->smac);

        char dmac_char[18] = "f8:8c:21:26:cc:91";
        mac_char_to_u_char(dmac_char, &(frame_header->dmac));
        frame_header->type = 0x0008;

        // 构造IP头部
        ip_header->sour_ip.s_addr = inet_addr("192.168.66.104");
        ip_header->dest_ip.s_addr = inet_addr("114.114.114.114");
        ip_header->vension_and_header = 0x45;
        ip_header->type_of_service = 0x00;
        // ip_header->lenght_of_packet=htons(len_ip_header+len_icmp_echo);
        ip_header->lenght_of_packet = 0x2e00;
        ip_header->id = 0xdc07;
        ip_header->flags_and_slice_info = 0x0000;
        ip_header->ttl = 0x40;
        ip_header->type_of_protocol = 0x01;
        // ip_header->checksum = htons(calculate_checksum((u_int16_t *)ip_header, len_ip_header));

        // // 构造ICMP 头部
        icmp_echo->type = 0x8;
        icmp_echo->code = 0x0;
        icmp_echo->seq = 0x0100;
        icmp_echo->ident = 0x0100;
        icmp_echo->checksum = 0x00;
        gettimeofday(&(icmp_echo->tv), NULL);
        // icmp_echo->checksum = htons(calculate_checksum((u_int16_t *)icmp_echo, len_icmp_echo + 2));

        int lenght_of_packet = len_frame_header + len_ip_header + len_icmp_echo;
        u_char buf[60];
        u_char buffer[MAX_PACKET_SIZE];

        if (ring == NULL)
            return -1;

        if (pfring_enable_ring(ring) != 0)
        {
            printf("Unable to enable ring :-(\n");
            pfring_close(ring);
            return (-1);
        }
        printf("len_info:%d %d %d \n", len_frame_header, len_ip_header, len_icmp_echo);
        for (int i = 1; i <= 200; i++)
        {

            icmp_echo->seq = htons(i % 65535);
            icmp_echo->checksum = htons(0);
            ip_header->checksum = htons(0);
            ip_header->checksum = htons(calculate_checksum((u_int16_t *)ip_header, len_ip_header));
            icmp_echo->checksum = htons(calculate_checksum((u_int16_t *)icmp_echo, len_icmp_echo));

            memset(buf, 0, 60);
            memcpy(buf, frame_header, len_frame_header);
            memcpy(buf + len_frame_header, ip_header, len_ip_header);
            memcpy(buf + len_frame_header + len_ip_header, icmp_echo, len_icmp_echo);

            pfring_send(ring, (char *)buf, 60, 1);

            // for (int i = 0; i < lenght_of_packet; i++)
            // {
            //     printf("%x ", *(buf + i));
            //     if (i == 13)
            //         printf("\n");
            //     if (i > 14 && (i - 14) % 4 == 3)
            //         printf("\n");
            // }
            // sleep(1);
        }

        printf("send\n");
        sleep(5);
    }
}